package data

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"sieve_admin_server_userpass/pkg/im3/db"
	"sieve_admin_server_userpass/pkg/redis"
)

func GetMemberVersion() (int64, error) {
	ver := int64(0)
	err := db.Mysql().QueryRow("SELECT SUM(`Ver`) as v FROM `User`").Scan(&ver)
	return ver, err
}

func GetUserPubKeyByUid(uid int) (string, error) {
	var pubkey string
	err := db.Mysql().QueryRow("SELECT `PubKey` FROM `User` WHERE `Uid`=?", uid).Scan(&pubkey)
	return pubkey, err
}

func GetUserNameByUid(uid int) (string, error) {
	var name string
	err := db.Mysql().QueryRow("SELECT `Name` FROM `User` WHERE `Uid`=?", uid).Scan(&name)
	return name, err
}

func GetUserDefaultDeptByUid(uid int) (int, error) {
	var did int
	err := db.Mysql().QueryRow("SELECT `Dept` FROM `User` WHERE `Uid`=?", uid).Scan(&did)
	return did, err
}

type UserData struct {
	Uid     int
	Name    string
	Email   string
	PubKey  string
	Dept    int
	Leader  int
	Company int
	// Avatar string
}

func GetUserByUid(uid int) (*UserData, error) {
	data := &UserData{Uid: uid}
	if err := db.Mysql().QueryRow("SELECT `Name`,`Email`,`PubKey`,`Dept`,`Leader`,`Company` FROM `User` WHERE `Uid`=?", uid).Scan(
		&data.Name,
		&data.Email,
		&data.PubKey,
		&data.Dept,
		&data.Leader,
	); err != nil {
		return nil, err
	}
	return data, nil
}

func GetUserList() ([]*UserData, error) {
	rows, err := db.Mysql().Query("SELECT `Uid`,`Name`,`Email`,`PubKey`,`Dept`,`Leader` FROM `User` WHERE `Pwd`!='' AND `PubKey`!=''")
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	list := []*UserData{}
	for rows.Next() {
		m := &UserData{}
		if err := rows.Scan(
			&m.Uid,
			&m.Name,
			&m.Email,
			&m.PubKey,
			&m.Dept,
			&m.Leader,
		); err != nil {
			return nil, err
		}
		list = append(list, m)
	}

	return list, nil
}

func GetAllUids() ([]int, error) {
	rows, err := db.Mysql().Query("SELECT `Uid` FROM `User` WHERE `Pwd`!='' AND `PubKey`!=''")
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	uids := []int{}
	for rows.Next() {
		var uid int
		if err := rows.Scan(&uid); err != nil {
			return nil, err
		}
		uids = append(uids, uid)
	}

	return uids, nil
}

func GetCompanyUids() ([]int, error) {
	rows, err := db.Mysql().Query("SELECT `Uid` FROM `User` WHERE `Pwd`!='' AND `PubKey`!='' AND `Company`>0")
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	uids := []int{}
	for rows.Next() {
		var uid int
		if err := rows.Scan(&uid); err != nil {
			return nil, err
		}
		uids = append(uids, uid)
	}

	return uids, nil
}

func GetUserListByUids(uids []int) ([]*UserData, error) {
	if len(uids) == 0 {
		return []*UserData{}, nil
	}
	suids := []string{}
	for _, uid := range uids {
		suids = append(suids, strconv.Itoa(uid))
	}
	rows, err := db.Mysql().Query("SELECT `Uid`,`Name`,`Email`,`PubKey`,`Dept` FROM `User` WHERE `Uid` IN (" + strings.Join(suids, ",") + ") AND `Pwd`!='' AND `PubKey`!=''")
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	list := []*UserData{}
	for rows.Next() {
		m := &UserData{}
		if err := rows.Scan(
			&m.Uid,
			&m.Name,
			&m.Email,
			&m.PubKey,
			&m.Dept,
		); err != nil {
			return nil, err
		}
		list = append(list, m)
	}

	return list, nil
}

func GenPwdHash(uid int, pwd string) string {
	salt := SHA1(strconv.Itoa(uid) + time.Now().String())
	return SHA1(pwd+salt) + salt
}

func SHA1(s string) string {
	h := sha1.New()
	h.Write([]byte(s))
	return fmt.Sprintf("%x", h.Sum(nil))
}

func VerifyPwd(uid int, pwd string) (bool, error) {
	savedPwd := ""
	if err := db.Mysql().QueryRow("SELECT `Pwd` FROM `User` WHERE `Uid`=?", uid).Scan(&savedPwd); err != nil {
		return false, err
	}
	if len(savedPwd) != 80 {
		return false, errors.New("data error")
	}
	return SHA1(pwd+savedPwd[40:]) == savedPwd[:40], nil
}

/*
var (
	fLimitUids = config.Strings("limit.uids", []string{"5000-5999"}, "受限用户")
	limitUids  = [][]int{}
)

func init() {
	app.OnStart(func() {
		config.OnReload(loadLimitUids)
		loadLimitUids()
	})
}

func loadLimitUids() {
	limits := [][]int{}
	for _, s := range *fLimitUids {
		ss := strings.Split(s, "-")
		if len(ss) != 2 {
			continue
		}
		min, err := strconv.Atoi(strings.TrimSpace(ss[0]))
		if err != nil {
			log.Err(err)
			continue
		}
		max, err := strconv.Atoi(strings.TrimSpace(ss[1]))
		if err != nil {
			log.Err(err)
			continue
		}
		if min > max {
			continue
		}
		limits = append(limits, []int{min, max})
	}
	limitUids = limits
}

func IsUidLimited(uid int) bool {
	for _, l := range limitUids {
		if uid >= l[0] && uid <= l[1] {
			return true
		}
	}
	return false
}
*/
//

func GetUserConfig(uid int, field string) (string, error) {
	v, err := db.Redis().Hash(db.UserKey(uid, "Config")).HGet(field).String()
	if err == redis.ErrNil {
		err = nil
	}
	return v, err
}

//

type Company struct {
	Cid  int
	Name string
}

func GetUserCompany(uid int) (*Company, error) {
	c := &Company{}
	if err := db.Mysql().QueryRow("SELECT `Cid`,`Name` FROM `Company` WHERE `Cid`=(SELECT `Company` FROM `User` WHERE `Uid`=?)", uid).Scan(&c.Cid, &c.Name); err != nil {
		return nil, err
	}
	return c, nil
}

func GetUserCompanyName(uid int) string {
	var name string
	db.Mysql().QueryRow("SELECT `Name` FROM `Company` WHERE `Cid`=(SELECT `Company` FROM `User` WHERE `Uid`=?)", uid).Scan(&name)
	return name
}

func GetUserCompanyId(uid int) int {
	var cid int
	db.Mysql().QueryRow("SELECT `Company` FROM `User` WHERE `Uid`=?", uid).Scan(&cid)
	return cid
}
